#pragma once

#include "ActivityNode.h"

#include "Activity.h"
#include "ActivityEdge.h"
#include "ActivityGroup.h"
#include "ActivityPartition.h"
#include "InterruptibleActivityRegion.h"
#include "RedefinableElement.h"
#include "StructuredActivityNode.h"

namespace uml {

ActivityNode::ActivityNode(const QString& umlType)
    : NamedElement(umlType) {}

void ActivityNode::fromJson(const QJsonObject& json, QStringList& errorList) {
    if (json.isEmpty()) {
        return;
    }

    NamedElement::fromJson(json, errorList);
    RedefinableElement::fromJson(json, errorList);
    activity_ = JsonSerializable::create<Activity>(json.value("activity"), errorList);

    JsonSerializable::fromJsonArray(inGroups_, "inGroups", json, errorList);
    JsonSerializable::fromJsonArray(inInterruptibleRegions_, "inInterruptibleRegions", json, errorList);
    JsonSerializable::fromJsonArray(inPartitions_, "inPartitions", json, errorList);
    inStructuredNode_ = JsonSerializable::create<StructuredActivityNode>(json.value("inStructuredNode"), errorList);

    JsonSerializable::fromJsonArray(incomings_, "incomings", json, errorList);
    JsonSerializable::fromJsonArray(outgoings_, "outgoings", json, errorList);
    JsonSerializable::fromJsonArray(redefinedNodes_, "redefinedNodes", json, errorList);
}

void ActivityNode::toJson(QJsonObject& json) {
    NamedElement::toJson(json);
    RedefinableElement::toJson(json);
    if (activity_) {
        QJsonObject activity_json;
        activity_->toJson(activity_json);
        json.insert("activity", activity_json);
    }
    JsonSerializable::toJsonArray(inGroups_, "inGroups", json);
    JsonSerializable::toJsonArray(inInterruptibleRegions_, "inInterruptibleRegions", json);
    JsonSerializable::toJsonArray(inPartitions_, "inPartitions", json);
    if (inStructuredNode_) {
        QJsonObject inStructuredNode_json;
        inStructuredNode_->toJson(inStructuredNode_json);
        json.insert("inStructuredNode", inStructuredNode_json);
    }
    JsonSerializable::toJsonArray(incomings_, "incomings", json);
    JsonSerializable::toJsonArray(outgoings_, "outgoings", json);
    JsonSerializable::toJsonArray(redefinedNodes_, "redefinedNodes", json);
}

/// <summary>
/// containingActivity
    /// The Activity that directly or indirectly contains this ActivityNode.
/// </summary>
    /// <code>
    /// result = (if inStructuredNode<>null then inStructuredNode.containingActivity()
    /// else activity
    /// endif)
    /// </code>
shared_ptr<Activity> ActivityNode::containingActivity() const
{
    return nullptr;
}

/// <summary>
/// isConsistentWith
/// </summary>
    /// <code>
    /// result = (redefiningElement.oclIsKindOf(ActivityNode))
    /// </code>
bool ActivityNode::isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const
{
    return false;
}

/// <summary>
/// activity getter
/// The Activity containing the ActivityNode, if it is directly owned by an
/// Activity.
/// </summary>
shared_ptr<Activity> ActivityNode::activity() const {
    return activity_;
}

/// <summary>
/// activity setter
/// The Activity containing the ActivityNode, if it is directly owned by an
/// Activity.
/// </summary>
void ActivityNode::setActivity(shared_ptr<Activity> value) {
    activity_ = value;
}

/// <summary>
/// inGroups getter
/// ActivityGroups containing the ActivityNode.
/// </summary>
vector<shared_ptr<ActivityGroup>>& ActivityNode::inGroups() {
    return inGroups_;
}

/// <summary>
/// inInterruptibleRegions getter
/// InterruptibleActivityRegions containing the ActivityNode.
/// </summary>
vector<shared_ptr<InterruptibleActivityRegion>>& ActivityNode::inInterruptibleRegions() {
    return inInterruptibleRegions_;
}

/// <summary>
/// inPartitions getter
/// ActivityPartitions containing the ActivityNode.
/// </summary>
vector<shared_ptr<ActivityPartition>>& ActivityNode::inPartitions() {
    return inPartitions_;
}

/// <summary>
/// inStructuredNode getter
/// The StructuredActivityNode containing the ActvityNode, if it is directly owned
/// by a StructuredActivityNode.
/// </summary>
shared_ptr<StructuredActivityNode> ActivityNode::inStructuredNode() const {
    return inStructuredNode_;
}

/// <summary>
/// inStructuredNode setter
/// The StructuredActivityNode containing the ActvityNode, if it is directly owned
/// by a StructuredActivityNode.
/// </summary>
void ActivityNode::setInStructuredNode(shared_ptr<StructuredActivityNode> value) {
    inStructuredNode_ = value;
}

/// <summary>
/// incomings getter
/// ActivityEdges that have the ActivityNode as their target.
/// </summary>
vector<shared_ptr<ActivityEdge>>& ActivityNode::incomings() {
    return incomings_;
}

/// <summary>
/// outgoings getter
/// ActivityEdges that have the ActivityNode as their source.
/// </summary>
vector<shared_ptr<ActivityEdge>>& ActivityNode::outgoings() {
    return outgoings_;
}

/// <summary>
/// redefinedNodes getter
/// ActivityNodes from a generalization of the Activity containining this
/// ActivityNode that are redefined by this ActivityNode.
/// </summary>
vector<shared_ptr<ActivityNode>>& ActivityNode::redefinedNodes() {
    return redefinedNodes_;
}

} // namespace uml
